package educrypt.commons;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.NoSuchElementException;

import educrypt.analysis.AnalysisNgrams;
import educrypt.commons.util.TextUtil;

public class Text implements Iterable<Character> {

	private String name;
	private String content;
	private String type;
	private String language;
	private String hash;

	public Text() {
		name = content = type = language = hash = "";
	}

	public Text(String content) {
		this.content = content;
	}

	public Text(String name, String type, String language, String content) {
		this.name = name;
		this.type = type;
		this.language = language;
		this.content = content;
	}

	private Text(Text text) {
		this.name = text.name;
		this.content = text.content;
		this.type = text.type;
		this.language = text.language;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public char getSymbolAt(int index) {
		return this.content.charAt(index);
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	public void setHash(String hash) {
		if (content == null || content.equals("")) {
			this.hash = hash;
		}
	}

	public int size() {
		return this.content.length();
	}

	public Text removeUnknownSymbols(Alphabet knownSymbols) {
		Text textWithoutUnknownContent = new Text(this);
		textWithoutUnknownContent.setContent(knownSymbols
				.filterKnownSymbols(this.content));
		return textWithoutUnknownContent;
	}

	public String getContentHash() {
		String hash = "";
		if (content == null || (content.equals("") && !this.hash.equals(""))) {
			hash = this.hash;
		} else {
			try {
				MessageDigest msgDigest = MessageDigest.getInstance("MD5");
				byte[] content = this.getContent().getBytes();
				msgDigest.update(content, 0, content.length);
				byte[] MD5 = msgDigest.digest();
				hash = formatToHex(MD5);
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			}
		}
		return hash;
	}

	private static String formatToHex(byte[] toTransform) {
		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < toTransform.length; i++) {
			String hex = Integer.toHexString(0xFF & toTransform[i]);
			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
		}
		return hexString.toString();
	}

	public AnalysisNgrams toNgramCollection(int ngramSize, Alphabet knownSymbols) {
		String text = this.getContent();
		String textLowerCase = text.toLowerCase();
		String textWithoutSpaces = TextUtil.removeWhiteSpaces(textLowerCase);
		AnalysisNgrams textNgramCollection = new AnalysisNgrams(
				textWithoutSpaces, ngramSize, AnalysisNgrams.OVERLAPING);
		return this.removeNgramsWithUnkownSymbols(textNgramCollection,
				knownSymbols);
	}

	public AnalysisNgrams toNgramCollectionNoOverlaping(int ngramSize,
			Alphabet knownSymbols) {
		String text = this.getContent();
		String textLowerCase = text.toLowerCase();
		String textWithoutSpaces = TextUtil.removeWhiteSpaces(textLowerCase);
		AnalysisNgrams textNgramCollection = new AnalysisNgrams(
				textWithoutSpaces, ngramSize, AnalysisNgrams.NO_OVERLAPING);
		return this.removeNgramsWithUnkownSymbols(textNgramCollection,
				knownSymbols);
	}

	private AnalysisNgrams removeNgramsWithUnkownSymbols(AnalysisNgrams ngrams,
			Alphabet knownSymbols) {
		AnalysisNgrams ngramsWithKnownSymbols = new AnalysisNgrams();
		for (String ngramToTest : ngrams) {
			if (knownSymbols.testBelonging(ngramToTest)) {
				ngramsWithKnownSymbols.addNgram(ngramToTest);
			}
		}
		return ngramsWithKnownSymbols;
	}

	public String toString() {
		String textToString = "NAME: " + this.name + "\n";
		textToString += "TYPE: " + this.type + "\n";
		textToString += "LANG: " + this.language + "\n";
		textToString += "CONTENT PREVIEW: " + this.content.substring(0, 30)
				+ " ...\n";
		textToString += "CONTENT HASH: " + this.getContentHash() + "\n";
		return textToString;
	}

	@Override
	public Iterator<Character> iterator() {
		return new TextIterator(this);

	}

	private class TextIterator implements Iterator<Character> {
		private Text text;
		private int index;

		public TextIterator(Text text) {
			this.text = text;
		}

		@Override
		public boolean hasNext() {
			return index < this.text.content.length();
		}

		@Override
		public Character next() {
			if (!hasNext()) {
				throw new NoSuchElementException();
			}
			return this.text.content.charAt(index++);
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
}
